<!DOCTYPE html>


<html lang="en">


<head>
  <meta charset="utf-8" />
   
  <meta name="keywords" content="学习" />
   
  <meta name="description" content="G.zero的个人博客" />
  
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
  <title>
     yang-blog
  </title>
  <meta name="generator" content="hexo-theme-ayer">
  
  <link rel="shortcut icon" href="/favicon.ico" />
  
  
<link rel="stylesheet" href="/dist/main.css">

  
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Shen-Yu/cdn/css/remixicon.min.css">

  
<link rel="stylesheet" href="/css/custom.css">

  
  
<script src="https://cdn.jsdelivr.net/npm/pace-js@1.0.2/pace.min.js"></script>

  
  

  

</head>

</html>

<body>
  <div id="app">
    
      
    <main class="content on">
      
<section class="cover">
    
  <div class="cover-frame">
    <div class="bg-box">
      <img src="/images/cover1.jpg" alt="image frame" />
    </div>
    <div class="cover-inner text-center text-white">
      <h1><a href="/">yang-blog</a></h1>
      <div id="subtitle-box">
        
        <span id="subtitle"></span>
        
      </div>
      <div>
        
      </div>
    </div>
  </div>
  <div class="cover-learn-more">
    <a href="javascript:void(0)" class="anchor"><i class="ri-arrow-down-line"></i></a>
  </div>
</section>



<script src="https://cdn.jsdelivr.net/npm/typed.js@2.0.11/lib/typed.min.js"></script>


<!-- Subtitle -->

  <script>
    try {
      var typed = new Typed("#subtitle", {
        strings: ['为学当如群山式，一峰突起众峰环', '愿你一生努力，一生被爱', '想要的都拥有，得不到的都释怀'],
        startDelay: 0,
        typeSpeed: 200,
        loop: true,
        backSpeed: 100,
        showCursor: false
      });
    } catch (err) {
      console.log(err)
    }
  </script>
  
<div id="main">
  <section class="outer">
  
  

<div class="notice" style="margin-top:50px">
    <i class="ri-heart-fill"></i>
    <div class="notice-content" id="broad"></div>
</div>
<script type="text/javascript">
    fetch('https://v1.hitokoto.cn')
        .then(response => response.json())
        .then(data => {
            document.getElementById("broad").innerHTML = data.hitokoto;
        })
        .catch(console.error)
</script>

<style>
    .notice {
        padding: 20px;
        border: 1px dashed #e6e6e6;
        color: #969696;
        position: relative;
        display: inline-block;
        width: 100%;
        background: #fbfbfb50;
        border-radius: 10px;
    }

    .notice i {
        float: left;
        color: #999;
        font-size: 16px;
        padding-right: 10px;
        vertical-align: middle;
        margin-top: -2px;
    }

    .notice-content {
        display: initial;
        vertical-align: middle;
    }
</style>
  
  <article class="articles">
    
    
    
    
    <article
  id="post-jvm/java-jvm-gc-memory"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2019/05/28/jvm/java-jvm-gc-memory/"
    >java内存分配与回收策略</a> 
</h2>
 

    </header>
     
    <div class="article-meta">
      <a href="/2019/05/28/jvm/java-jvm-gc-memory/" class="article-date">
  <time datetime="2019-05-28T07:43:05.000Z" itemprop="datePublished">2019-05-28</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/JAVA-JVM/">JAVA_JVM</a>
  </div>
   
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <p>大多数的情况下，对象在新生代Eden区中分配。当Eden没有足够的空间进行分配时，虚拟机会触发一次Minor GC。</p>
<p>大对象是指需要大量连续内存空间的java对象，最典型的大对象是那种很长的字符串以及数组。</p>
<p>-XX:pretenureSizeThreshold参数，令大于设置值的对象直接分配到老年代中，从而避免对象在Eden区与Survivor区之间发生大量复制。</p>
<p>虚拟机通常采用分代收集的思想来管理内存。虚拟机为每个对象定义了一个对象年龄计数器，如果对象在Eden区经过了一次Minor GC 还存活， 那么该对象会进入Survivor中，并且age设置为1。每经过一次Minor GC age都会加1，直到达到一定程度（默认是15岁），会进入到老年代。年龄阈值通过参数-XX:MaxTenuringThreshold设置。</p>
<p>为了更好的适应不同程序的内存状况，虚拟机并不是永远的要求对象的年龄必须达到了参数才能晋升到老年代，如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的1半，年龄大于或者等于改年龄的对象接可以直接进入老年代，不用等到MaxTenuringThreshold中的年龄要求。</p>
<p><font color= "red">注：</font></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Minor GC(新生代GC)：指发生在新生代的垃圾收集动作，触发频率频繁，回收速度也比较快。</span><br><span class="line"></span><br><span class="line">Major GC&#x2F;Full GC(老年代GC)：指发生在老年代的GC，出现Major GC，经常伴随至少一次的Minor GC。</span><br></pre></td></tr></table></figure> 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/JVM/" rel="tag">JVM</a></li></ul>

    </footer>
  </div>

    
 
   
</article>

    
    <article
  id="post-jvm/java-jvm-gc-algorithm-1"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2019/05/27/jvm/java-jvm-gc-algorithm-1/"
    >垃圾回收器算法的实现</a> 
</h2>
 

    </header>
     
    <div class="article-meta">
      <a href="/2019/05/27/jvm/java-jvm-gc-algorithm-1/" class="article-date">
  <time datetime="2019-05-27T07:49:28.000Z" itemprop="datePublished">2019-05-27</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/JAVA-JVM/">JAVA_JVM</a>
  </div>
   
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <h2 id="HOTSPOT算法实现"><a href="#HOTSPOT算法实现" class="headerlink" title="HOTSPOT算法实现"></a>HOTSPOT算法实现</h2><h3 id="枚举根节点"><a href="#枚举根节点" class="headerlink" title="枚举根节点"></a>枚举根节点</h3><p>GC Roots主要在全局性的引用（例如常量或者类静态属性）与执行上下文（例如栈帧中的本地变量表）中，java进行可达性分析时，对执行时间的敏感还体现在GC停顿上，因为分析工作必须在一个能确保一致性（分析过程中对象引用关系不能再不断变化）的快照中进行，这点是导致GC进行时必须停顿所有的java执行线程的一个重要原因。即使是在GMS收集器中，枚举枚举根节点也要停顿。</p>
<p>在HotSpot中使用OopMap的数据结构来保存对象的引用，从而在执行分析时不需要一个不漏的检查完所有的执行上下文和全局的引用位置，在类加载完成的时候，HotSpot就把对象内什么偏移量上是什么类型的数据计算出来，在JIT编译过程中，也会在特定的位置记录下栈和寄存器中哪些位置是引用。</p>
<h3 id="安全点"><a href="#安全点" class="headerlink" title="安全点"></a>安全点</h3><p>HotSpot没有为每条指令都生成OopMap，只是在特定的位置记录了这些信息，就是安全点（SafePoint）。即程序执行时并非在所有的地方都要停顿下来开始GC，只有到达安全点才能暂停。<br>SafePoint选定太少会让gc等待时间太长，太多会增加运行时的负荷。</p>
<p>所以安全点的选定基本是以程序“是否具有让程序长时间执行的特征”为标准进行选定的-因为每条指令执行时间都非常短暂，程序不太可能因为指令流长度太长这个原因而过长时间运行。“长时间执行”的最明显特征就是指令序列复用，例如方法调用，循环跳转，异常跳转等，所有具有这些功能的指令才会产生SafePoint。</p>
<p>对于SafePoint，另一个需要考虑的问题是如何在GC发生时让所有线程都跑到最近的安全点上在停顿下来。有两个方案：</p>
<ul>
<li>抢先式中断</li>
</ul>
<p>不需要线程的执行代码主动去配合，在GC发生时，首先把所有线程全部中断，如果发现有线程中断的地方不在安全点上，就恢复线程，让它跑到安全点上。</p>
<ul>
<li>主动式中断</li>
</ul>
<p>当GC需要中断线程的时候，不直接对线程操作，仅设置一个标志，各个线程执行时主动去轮询这个标志，发现中断标志位真就自己中断挂起。轮询标志的地方和安全点是重合的，另外在加上创建对象需要分配内存的地方。</p>
<h3 id="安全区域"><a href="#安全区域" class="headerlink" title="安全区域"></a>安全区域</h3><p>安全区域是指在一段代码片段之中，引用关系不会发生变化。在这个区域中的任意地方开始GC都是安全的。<br>在线程执行到安全区域中的代码时，首先标识自己进入了安全区域，当在这段时间里JVM要发起GC时，就不用管标识自己为安全区域状态的线程了，在线程要离开安全区域，要检查是否已经完成了根节点枚举，如果完成了那现场就继续执行，否则必须等待直到收到可以离开安全区域的信号位置。</p>
<h2 id="垃圾收集器"><a href="#垃圾收集器" class="headerlink" title="垃圾收集器"></a>垃圾收集器</h2><p>收集算法是内存回收的方法理论，垃圾收集器就是内存回收的具体实现。java虚拟机规范没有对垃圾收集器如何实现有规定，因此不同厂商、版本提供的垃圾收集器可能大不相同。</p>
<blockquote>
<p><font color='green'>Serial(/sɪəriəl/)收集器</font></p>
</blockquote>
<p>Serial 收集器是最基本、历史最悠久的收集器。这个收集器是一个单线程的收集器，单线程的意义不仅仅说明它是只会使用一个CPU或一条收集线程去完成垃圾收集工作，更重要的是它进行垃圾收集时，必须暂停其他所有的工作线程，直到收集完成。</p>
<p><img src="./serial.png" alt="serial.png"></p>
<p>目前为止，Serial依然是虚拟机运行在Client模式下的默认新生代收集器。<br>优点：<br>简单，高效。对于限定单个CPU的环境来说，Serial收集器由于没有线程交互的开销，专心做垃圾收集自然可以获得最高的单线程收集小路。</p>
<blockquote>
<p><font color='green'>ParNew收集器</font></p>
</blockquote>
<p>parNew收集器其实就是Serial收集器的多线程版本，HotSpot第一款真正意义上的并发收集器</p>
<p><img src="./parnew.png" alt="parnew.png"></p>
<p>参数：</p>
<ul>
<li>-XX:+UseConcMarkSweepGC：选择后的默认新生代收集器</li>
<li>-XX:+UserParNewGC:强制指定</li>
<li>-XX:ParallelGCThreads：限制垃圾收集线程数</li>
</ul>
<blockquote>
<p><font color='green'>Parallel Scavenge收集器</font></p>
</blockquote>
<p>新生代收集器、使用复制算法、并行的多线程收集器。</p>
<p>特点：<br>关注点与其他收集器不同。CMS等收集器关注点是尽可能的缩短垃圾回收时用户线程停顿的时间，而Parallel Scavenge收集器目的则是达到一个可控制的吞吐量。吞吐量就是CPU运行用户代码时间与CPU总消耗时间的比值，即吞吐量=运行代码时间/(运行代码时间+垃圾收集时间)。</p>
<p>停顿时间越短越适合需要与用户交互的程序，良好的响应速度能提升用户体验，而高吞吐量则可以高效的利用CPU时间，尽快完成程序的运算任务，主要适合后台运算而不需要太多交互的任务。</p>
<p>参数：</p>
<ul>
<li>-XX:MaxGCPauseMillis:控制最大垃圾收集停顿时间</li>
</ul>
<p>参数值是一个大于0的毫米数，收集器尽可能保证内存回收花费的时间不超过设定值。不是说参数调至越小垃圾收集的时间越快，GC停顿时间压缩是以牺牲吞吐量和新生代空间来换取的。</p>
<ul>
<li><p>-XX:GCTimeRatil:设置吞吐量大小<br>参数值是一个大于0且小于100的整数，也就是垃圾收集时间占总时间的比率，相当于吞吐量倒数，如果参数设置为19，那么预先的最大GC时间占总时间的5%（1/(1+19)）,默认为99，就是允许最大1%（1/(1+99)）的垃圾收集时间。</p>
</li>
<li><p>-XX:UseAdaptiveSizePolicy:这个一个开关参数，打开后，不需要手动指定新生代的大小、Eden和Survivor区的比例，晋升老年代对象年龄等细节参数，会动态调整这些参数以提供最适合的停顿时间或者最大的吞吐量。</p>
</li>
</ul>
<blockquote>
<p><font color='green'>Serial Old 收集器</font></p>
</blockquote>
<p>Serial Older 是 Serial 收集器的老年代版本，同样是一大单线程收集器，使用标记-整理算法。</p>
<blockquote>
<p><font color='green'>Parallel Old 收集器</font></p>
</blockquote>
<p>Parallel Old 是 Parallel Scavenge 收集器的老年代版本，使用多线程和标记-整理算法。</p>
<blockquote>
<p><font color='green'>CMS 收集器</font></p>
</blockquote>
<p>CMS(Concurent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前java集中在互联网网站或者B/S系统服务端，比较重视服务响应时间，给用户带来比较好的体验，CMS非常服务符合这类需求。</p>
<p>CMS采用标记-清除算法，整个步骤包括：</p>
<ul>
<li>初始标记（CMS initial mark）<br>仅仅标记一下GC Roots能直接关联到的对象，速度很快。</li>
<li>并发标记（CMS concurrent mark）<br>进行GC Roots Tracing的过程</li>
<li>重新标记（CMS remark）<br>为了修正并发标记期间因用户程序继续运作而导致标志产生变动的那一部分对象的标记记录，这个阶段停顿时间一般会比初始化阶段稍长一些，但远比并发标记的时间短。</li>
<li>并发清除（CMS concurrent sweep）</li>
</ul>
<p>初始标记和重新标记步骤任然需要“stop the world”。整个过程中耗时比较长的并发标记和并发清除过程是与用户线程一起工作的。</p>
<p><img src="./cms.png" alt="cms.png"></p>
<p><strong>优点</strong><br>并发收集，低停顿</p>
<p><strong>缺点</strong></p>
<ul>
<li>对CPU资源非常敏感<br>并发阶段，它不会导致用户线程停顿，但是会因为占用了一部分线程而导致应用程序变慢，总吞吐会降低。</li>
<li>无法处理浮动垃圾，可能出现“Concurrent Mode Failure”失败而导致另一次 Full GC。</li>
<li>产生大量空间碎片 </li>
</ul>
<blockquote>
<p><font color="green">G1收集器</font></p>
</blockquote>
<p>G1是面向服务端的垃圾收集器。</p>
<p><strong>特点</strong></p>
<ul>
<li>并行与并发<br>充分利用多CPU多核环境下的硬件优势，缩短stop the world停顿时间。</li>
<li>分代收集</li>
<li>空间整合<br>G1 从整体来看基于标记-整理算法实现，从局部看基于复制算法实现，运行期间不会产生内存碎片。</li>
<li>可预测的停顿</li>
</ul>
<p><strong>步骤</strong></p>
<ul>
<li>初始标记</li>
<li>并发标记</li>
<li>最终标记</li>
<li>筛选回收</li>
</ul>
<p>初始标记仅仅是标记下GC Roots能直接关联到的对象，并且修改TAMS（next top at mark start）的值，让下一阶段用户程序并发运行时，能在正确可用的Region中创建新对象，这一阶段需要停顿线程。<br>并发标记是从GC Roots开始对堆中对象进行可达性分析，找到存活的对象，这段耗时长，但可与用户程序并发执行。<br>最终标记是为了修正并发标记期间因用户程序继续运作而导致标记发生变化的那一部分标记记录。<br>筛选回收首先对各个Region的回收价值和成本进行排序，根据用户所期望的GC停顿时间来制定回收计划。</p>
<h2 id="理解GC日志"><a href="#理解GC日志" class="headerlink" title="理解GC日志"></a>理解GC日志</h2><p>下面是一段GC日志：</p>
<p><img src="./GClog.png" alt="GClog.png"></p>
<p>“33.125：” 和 “100.67：” 代表GC发生的时间，是从java虚拟机启动以来经过的描述。</p>
<p>“[GC”和”[Full GC” 说明这次垃圾收集的停顿类型，而不是用来区分新生代还是老年代GC的。有 Full 说明这次GC是发生了“stop  the world”的。</p>
<p>“[DefNew”、”[Tenured”、”[Perm”标识GC发生区域，这里显示的区域名和使用的GC收集器是密切相关的。如果使用Serial收集器中的新生代名称”Default New Generation”，显示”[DefNew”。如果使用ParNew,则为”[Tenured”，使用Parallel Scavenge收集器，那它配套的新生代名称为”PSYoungGen” 老年代和永久代同理，名称由收集器决定。</p>
<p>“3324K-&gt;152K(3712k)”表示 GC前该内存区域已使用容量 -&gt; GC 后该内存区域已使用容量（该内存区域总容量）。</p>
<p>方括号之外的”3324K-&gt;152K(11904)” 表示 GC前java堆已使用容量-&gt;GC 后该java堆已使用容量（java堆总容量）。<br>“0.0025925 secs”表示内存区域GC所占用的时间，单位秒。</p>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/JVM/" rel="tag">JVM</a></li></ul>

    </footer>
  </div>

    
 
   
</article>

    
    <article
  id="post-jvm/java-jvm-gc-algorithm"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2019/05/27/jvm/java-jvm-gc-algorithm/"
    >垃圾收集算法</a> 
</h2>
 

    </header>
     
    <div class="article-meta">
      <a href="/2019/05/27/jvm/java-jvm-gc-algorithm/" class="article-date">
  <time datetime="2019-05-27T05:40:32.000Z" itemprop="datePublished">2019-05-27</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/JAVA-JVM/">JAVA_JVM</a>
  </div>
   
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <h3 id="1-标记-清除算法"><a href="#1-标记-清除算法" class="headerlink" title="1.标记-清除算法"></a>1.标记-清除算法</h3><p>标记-清除算法是最基础的收集算法。主要分为两步：标记，清除。首先标记处需要回收的对象，标记完成后统一回收被标记的对象。</p>
<p><font color='red'>缺点</font></p>
<ul>
<li>效率问题：标记和清除效率都不高</li>
<li>空间问题：标记清除后会产生大量不连续的内存碎片。如果程序在运行时需要分配较大的对象，无法找到足够大的内存就不能不提前触发另一次垃圾收集动作。</li>
</ul>
<p><img src="biaojiqingchu1.png" alt="biaojiqingchu1.png"></p>
<p><img src="biaojiqingchu2.png" alt="biaojiqingchu2.png"></p>
<h3 id="2-复制算法"><a href="#2-复制算法" class="headerlink" title="2.复制算法"></a>2.复制算法</h3><p>复制算法可以更好的解决效率的问题。它将内存分为两块同等大小的区域。每次只回收其中一块区域。当垃圾回收器开始回收时，会将使用的一块内存中还存活的对象复制到另一块内存，然后一次清空这块使用的内存，每次都是对整个半区进行内存回收，内存分配不用考虑内存碎片的问题，只要一动堆顶的指针，按顺序分配内存即可，简单，高效。</p>
<p>现在商业虚拟机都采用这种收集算法来回收新生代。通常将内存分为一块较大的Eden空间和两块比较小的Survivor空间，每次使用Eden和其中的一块Survivor，回收时，将Eden和Survivor中还存活的对象一次性复制到另一块Survivor空间上，最后清理掉Eden和刚才用到的Survivor空间。HotSpot默认Eden和Survivor比例是8:1，也就是每次新生代中可用空间为整个新生代容量的90%，只有10%的内存会被浪费。当Survivor空间不足时，需要依赖其他内存（老年代）进行分担担保。</p>
<p><img src="fuzhi1.png" alt="fuzhi1.png"></p>
<p><img src="fuzhi2.png" alt="fuzhi2.png"></p>
<h3 id="3-标记-整理算法"><a href="#3-标记-整理算法" class="headerlink" title="3.标记-整理算法"></a>3.标记-整理算法</h3><p>标记-整理算法，标记的过程和标记-清除算法一下，后续步骤不是直接回收对象，而是让所有存活的对象都向一端一动，然后直接清除掉端边界以外的内存。</p>
<p><img src="biaojizhengli.png" alt="biaojizhengli.png"></p>
<p><img src="biaojizhengli1.png" alt="biaojizhengli1.png"></p>
<h3 id="4-分代收集算法"><a href="#4-分代收集算法" class="headerlink" title="4.分代收集算法"></a>4.分代收集算法</h3><p>当前商业虚拟机的垃圾收集都采用分代收集算法，根据对象存活周期的不同将内存分为几块，java堆分为新生代和老年代，这样根据各个年代的特点采用适当的收集算法。新生代中每次都会有大量的对象死去，是有少量的存活，就选用复制算法。老年代中因为对象存活率高，没有额外的空间进行分配担保，就需要使用标记-清理或者标记整理算法进行回收。</p>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/JVM/" rel="tag">JVM</a></li></ul>

    </footer>
  </div>

    
 
   
</article>

    
    <article
  id="post-jvm/java-jvm-gc"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2019/05/24/jvm/java-jvm-gc/"
    >JVM学习笔记-垃圾回收机制</a> 
</h2>
 

    </header>
     
    <div class="article-meta">
      <a href="/2019/05/24/jvm/java-jvm-gc/" class="article-date">
  <time datetime="2019-05-24T08:06:15.000Z" itemprop="datePublished">2019-05-24</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/JAVA-JVM/">JAVA_JVM</a>
  </div>
   
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <p>&#160; &#160; &#160; &#160;我们来学习一下jvm中比较重要的一块内容-GC。那么我们学习了GC与内存分配，能做什么呢？ 当我们需要排除各种内存溢出、内存泄漏等问题时，当垃圾收集成为系统大道更高并发的瓶颈时，我们就需要对GC实施必要的监控和调节。</p>
<h3 id="哪些对象可变回收"><a href="#哪些对象可变回收" class="headerlink" title="哪些对象可变回收"></a>哪些对象可变回收</h3><p>&#160; &#160; &#160; &#160;垃圾回收器会定期回收堆内存中不在被使用的对象，通常判断对象是否需要被回收，有两种方式，引用计数法和可达性分析</p>
<h4 id="引用计数法"><a href="#引用计数法" class="headerlink" title="引用计数法"></a>引用计数法</h4><p>&#160; &#160; &#160; &#160;每个对象都有一个引用计数器，每当有一个地方引用该对象，引用计数就会+1，如果引用失效就会-1，当引用计数值为0的时候，这个对象就不在被使用。这种实现方式简单，判断效率高。但是他<font color='red'>存在一个问题，就是如果对象相互循环引用，那么这些对象就不能被回收</font>。java虚拟机没有采用这种实现方式。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">public class TestGC&#123;</span><br><span class="line"></span><br><span class="line">    public Object instance &#x3D; null;</span><br><span class="line">    private byte[] bigSize &#x3D; new byte[1024*1024*2];</span><br><span class="line"></span><br><span class="line">    public static void main(String[] args)&#123;</span><br><span class="line"></span><br><span class="line">        &#x2F;&#x2F; o1 和 o2 相互引用</span><br><span class="line">        TestGC o1 &#x3D; new TestGC();</span><br><span class="line">        TestGC o2 &#x3D; new TestGC();</span><br><span class="line">        o1.instance &#x3D; o2;</span><br><span class="line">        o2.instance &#x3D; o1;</span><br><span class="line"></span><br><span class="line">        &#x2F;&#x2F;此时两个对象都不能再被访问，但是他们相互引用对方，引用计数值都不是0</span><br><span class="line">        o1 &#x3D; null;</span><br><span class="line">        o2 &#x3D; null;</span><br><span class="line">        &#x2F;&#x2F;假设在这里发生GC，他们并不会被回收</span><br><span class="line">        System.gc();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<h4 id="可达性分析"><a href="#可达性分析" class="headerlink" title="可达性分析"></a>可达性分析</h4><p>&#160; &#160; &#160; &#160;从GC Roots开始向下搜索，搜索走过的路径称为引用链，当无法从GC Roots通过引用链到达某个对象，那么这个对象就是不可达，需要被回收。</p>
<p>java中，以下可作为GC Roots对象：</p>
<ul>
<li>虚拟机栈（栈帧中国的本地变量表）中引用的对象</li>
<li>方法区中类静态属性引用的对象</li>
<li>方法区中常量引用的对象</li>
<li>本地方法栈中JNI引用的对象</li>
</ul>
<p><img src="./GCRoots.png" alt="GC Roots"></p>
<h3 id="引用"><a href="#引用" class="headerlink" title="引用"></a>引用</h3><p>jdk1.2之后，java对引用进行了扩展，将引用分为强引用，软引用，弱引用和虚引用。四种引用强度一次逐渐减弱。</p>
<ul>
<li>强引用</li>
</ul>
<p>强引用在java代码中是最常见的， 当我们new一个对象的时候，就是一个强引用。只要强引用存在，垃圾回收机制就不会回收对象。</p>
<ul>
<li>软引用</li>
</ul>
<p>软引用是描述一些有用但是非必须的对象。系统在发生内存溢出之前，将会把这些对象列进回收范围之中进行第二次回收。如果系统存在足够的内存，这些对象不会被回收，如果内存不足，则会回收这些对象。java提供SoftReference类实现软引用。</p>
<ul>
<li>弱引用</li>
</ul>
<p>弱引用描述非必需对象的。弱引用的对象只能生存到下一次垃圾回收之前。当开始垃圾回收时，不过内存是否足够都会回收弱引用的对象。java提供WeakReference类来实现弱引用。</p>
<ul>
<li>虚引用</li>
</ul>
<p>一个对象是否有虚引用的存在，完全不会对其生存时间构成影响，也无法通过虚引用来取得一个对象实例。设置虚引用主要是为了该对象在垃圾收集器回收会收到一个系统通知。java提供PhantomReference类来实现。</p>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/JVM/" rel="tag">JVM</a></li></ul>

    </footer>
  </div>

    
 
   
</article>

    
    <article
  id="post-jvm/java-jvm-object"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2019/05/22/jvm/java-jvm-object/"
    >JVM学习笔记-java对象</a> 
</h2>
 

    </header>
     
    <div class="article-meta">
      <a href="/2019/05/22/jvm/java-jvm-object/" class="article-date">
  <time datetime="2019-05-22T07:47:30.000Z" itemprop="datePublished">2019-05-22</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/JAVA-JVM/">JAVA_JVM</a>
  </div>
   
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <p>&nbsp; &nbsp; &nbsp; &nbsp;我们在学习了java虚拟机的内存知识后，我们接下来研究下对象的在java堆中分配、布局和访问的全过程。</p>
<h3 id="对象的创建"><a href="#对象的创建" class="headerlink" title="对象的创建"></a><font color=#008000>对象的创建</font></h3><p>&nbsp; &nbsp; &nbsp; &nbsp;在我们开发的过程中，用到的最多的当然还是通过 new 关键字去创建一个对象，那么在创建是一个怎样的过程呢？</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp;1.在执行 new 指令时，会去检查这个指令的参数是否能在常量池中定位到一个类的符号引用。并且检查这个符号引入代表的类是否已被加载、解析和初始化。如果没有就需要就行响应的类加载过程。（加载过程后面会说）</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp;2.在类加载检查通过后，会为新生的对象分配内存空间，对象所需要的内存空间，在类加载完成后便可完全确定下来，为对象分配空间等同于在java堆中划分出一块内存。分配内存空间有两种分配方式：</p>
<ul>
<li>指针碰撞</li>
</ul>
<p>&nbsp; &nbsp; &nbsp; &nbsp;java堆的内存空间是<strong>规整</strong>的，使用的内存空间放在一起，空闲的内存空间放在一起，中间使用一个指针作为分界点的指示器。所分配的内存就是仅仅把指针箱空闲的那边挪动一段与对象大小相等的距离。</p>
<ul>
<li>空闲列表</li>
</ul>
<p>&nbsp; &nbsp; &nbsp; &nbsp;java堆内存空间不是<strong>规整</strong>的，使用的和没有使用的交错在一起，虚拟机会维护一个列表，记录上哪些内存块是可用的，在分配的时候从列表中找到一个块足够大的空间划分给对象实例，并更新列表上的记录。</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 具体使用哪种方式取决于java堆是否是规整的，而是否规整取决于垃圾收集器是否带有压缩整理功能决定。所以在使用Serial、ParNew等带有Compact过程的收集器，系统使用分配算法是指针碰撞，而使用CMS这种基于Mark-Sweep算法的采用空闲列表。<br>&nbsp; &nbsp; &nbsp; &nbsp;在划分空间的时候，如果频繁的创建对象，就会出现线程安全问题。比如两个线程A和B，虚拟机在为A分配内存的时候，指针还没有来得及修改，对象B同时使用了原来的指针来分配内存。决定方法有两种，<br>一种是使用CAS配上失败重试的方式保证更新操作的原子性。<br>另一种是按照线程的维度去分配空间。每个线程会预先分配到一小块的内存，称为<font color="red">本地线程分配缓冲（Thread Local Allocation Buffer,TLAB）</font>。需要分配内存的时候，在该线程的TLAB上去分配，只有TLAB用完了，并分配新的TLAB才需要同步锁定。通过-XX:+/-UseTLAB参数设置是否使用TLAB。</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp;3.分配内存后，虚拟机需要将分配的内存空间都初始化为零值。从而保证对象的实例字段在java代码中可以不赋初始值就可以直接使用。</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp;4.接下来要对对象进行必要的设置，例如这个对象是哪个类的实例，如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息，这些信息都存放在对象头中。</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp;5.完成上述工作，需要执行 init 方法，把对象按照程序员的意愿进行初始化。这样一个真正的对象才算完全生产出来。</p>
<h3 id="对象的内存布局"><a href="#对象的内存布局" class="headerlink" title="对象的内存布局"></a><font color=#008000>对象的内存布局</font></h3><p>&nbsp; &nbsp; &nbsp; &nbsp;对象的存储布局分为三个区域：对象头（Header）、实例数据（Instant Data）和对其填充（Padding）</p>
<h4 id="对象头"><a href="#对象头" class="headerlink" title="对象头"></a>对象头</h4><p>&nbsp; &nbsp; &nbsp; &nbsp;第一部分用于存储对象自身运行时数据，哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等，官方称为“Mark Word”。这部分数据的长度在32位和64位的虚拟机上分别是32bit 和 64bit。Mark Word 被设计成一个非固定的数据结构以便在极小的空间内存储更多的信息。他会根据对象的状态复用自己的存储空间。比如，在32位的HotSpot虚拟机上，如果对象处于未被锁定的状态下，那么Mark Word的32bit空间中，25bit用于存储对象的哈希码，4bit用于存储对象的分代年龄，2bit存储锁标志位，1bit固定为0。而其他状态下的存储如下。</p>
<table>
<thead>
<tr>
<th align="center">存储内容</th>
<th align="center">标志位</th>
<th align="center">状态</th>
</tr>
</thead>
<tbody><tr>
<td align="center">对象哈希码、对象分代年龄</td>
<td align="center">01</td>
<td align="center">未锁定</td>
</tr>
<tr>
<td align="center">指向锁记录的指针</td>
<td align="center">00</td>
<td align="center">轻量级锁</td>
</tr>
<tr>
<td align="center">执行重量级锁的指针</td>
<td align="center">10</td>
<td align="center">膨胀（重量级锁定）</td>
</tr>
<tr>
<td align="center">空，不需要记录信息</td>
<td align="center">11</td>
<td align="center">GC标志</td>
</tr>
<tr>
<td align="center">偏向线程ID、偏向时间戳、对象分代年龄</td>
<td align="center">01</td>
<td align="center">可偏向</td>
</tr>
</tbody></table>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 另一部分是类型指针。即对象指向它的类元数据的指针，虚拟机通过这个指针确定这个对象是哪个类的实例。但是不是所有的虚拟机都需要在对象数据上保留类型指针，也就是说查找对象的元数据信息并不是一定需要经过对象本身。如果对象是一个java数组，那对象头还需要一块用于记录数据长度的数据，因为虚拟机可以通过普通的java对象的元数据信息确定java对象的大小，但是从数据的元数据中无法确定数组的大小。</p>
<h3 id="实例数据"><a href="#实例数据" class="headerlink" title="实例数据"></a>实例数据</h3><p>&nbsp; &nbsp; &nbsp; &nbsp; 对象真正存储的有效信息。也是程序代码中所定义的各种类型的字段内容。无论是从父类继承下来的，还是在子类中定义的，都需要记录起来。</p>
<h3 id="对其填充"><a href="#对其填充" class="headerlink" title="对其填充"></a>对其填充</h3><p>&nbsp; &nbsp; &nbsp; &nbsp; 不是必然存在额，也没有特殊的意义，仅仅起着占位符的作用。HotSpot VM 的自动内存管理系统要求对象起始地址必须是8字节的整数倍。换句话，就是对象的大小必须是8字节的整数倍，而对象头部分正好是8字节的整数倍，因此当对象实例数据部分没有对齐时，就需要通过对齐填充来补充。</p>
<h3 id="对象的访问定位"><a href="#对象的访问定位" class="headerlink" title="对象的访问定位"></a><font color=#008000>对象的访问定位</font></h3><p>&nbsp; &nbsp; &nbsp; &nbsp;java程序通过栈上的reference数据来操作堆上的具体对象。reference类型在java虚拟机规范中只规定了一个指向对象的引用，并没有定义通过何种方式去定位、访问堆中对象的具体位置，所以对象访问方式取决于虚拟机事项而定。目前访问方式主要有两种：</p>
<ul>
<li>使用句柄</li>
</ul>
<p>java堆中会划分出一块内存来作为句柄池，reference中存储的是对象的句柄地址，而句柄包含了对象实例数据与类型数据各自的具体地址信息。</p>
<p>使用句柄最大的好处是reference中存储的是稳定的句柄地址，在对象被移动时只会改变句柄中的实例数据指针，而reference本身不需要修改。<br><img src="./jubinchi.png" alt="句柄池"></p>
<ul>
<li>直接指针</li>
</ul>
<p>java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息，而reference中存储的直接就是对象地址。</p>
<p>使用直接指针速度更快，由于对象访问在java中非常频繁，这类开销积少成多，也是一项非常可观的执行成本。HotSpot就是使用直接指针。</p>
<p><img src="./zhijiezhizhen.png" alt="直接指针"></p>
 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/JVM/" rel="tag">JVM</a></li></ul>

    </footer>
  </div>

    
 
   
</article>

    
    <article
  id="post-jvm/java-jvm-1"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2019/05/21/jvm/java-jvm-1/"
    >JVM学习笔记-运行时数据区域</a> 
</h2>
 

    </header>
     
    <div class="article-meta">
      <a href="/2019/05/21/jvm/java-jvm-1/" class="article-date">
  <time datetime="2019-05-21T07:35:37.000Z" itemprop="datePublished">2019-05-21</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/JAVA-JVM/">JAVA_JVM</a>
  </div>
   
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <p>&#160; &#160; &#160; &#160;​java虚拟机在运行java程序的时候，会将内存划分成不同的数据区域，每个区域负责不同的功能，通常分为：方法区、虚拟机栈、本地方法栈。接下来我们一一介绍这些概念。</p>
<p><img src="./jvm_area.png" alt="jvm_area.png"></p>
<h3 id="1-程序计数器"><a href="#1-程序计数器" class="headerlink" title="1.程序计数器"></a>1.程序计数器</h3><p>&#160; &#160; &#160; &#160;​程序计数器是一块非常小的内存，它是当前线程所执行的字节码的行号指示器。在虚拟机的概念里，字节码解释器是通过改变这个计数器的值来选取下一个需要执行的字节码指令， 分支、循环、异常处理、线程恢复都依赖这个程序计数器来完成。<br>&#160; &#160; &#160; &#160;java多线程执行是通过不停切换处理器来分别执行各个线程实现的，也就是同一时刻只有一个处理器只能执行一条线程，每个线程执行一段时间在执行其他的线程，所以每个线程都需要有自己独立的程序计数器，才能在处理器切回自己线程的时候，继续正确执行，所以<strong>程序计时器是线程私有的</strong>。<br>&#160; &#160; &#160; &#160;程序计数器是java虚拟机唯一一个没有OutOfMemoryError的区域。</p>
<h3 id="2-java虚拟机栈"><a href="#2-java虚拟机栈" class="headerlink" title="2.java虚拟机栈"></a>2.java虚拟机栈</h3><p>&#160; &#160; &#160; &#160;java虚拟机栈描述的是java方法执行的内存模型，每个方法执行的时候，会在创建一个栈帧，存储局部变量表、操作数栈、动态链接、方法出口等。同时栈是线程私有的，生命周期与线程相同。<br>&#160; &#160; &#160; &#160;局部变量表存放了编译器可知的各种基本数据类型（boolean，byte，char,short,int,float,long,double）、对象引用和returnAddress类型。<br>&#160; &#160; &#160; &#160;64位长度的long和double类型的数据会占用两个局部变量的空间，其余的数据类型都只占用1个空间。局部变量表需要的空间，在编译期间完成分配，当进入一个方法时，这个方法需要的在栈分配的大小是完全确定的在方法运行时，局部变量表的大小不会改变。<br>&#160; &#160; &#160; &#160;这个区域规定了两种异常状况：如果线程请求的栈深度大于虚拟机所允许的深度，会抛出StackOverFlowError异常。如果虚拟机栈可以动态扩展，如果扩展时无法申请到足够的内存，就会抛出OutOfMemoryError。</p>
<h3 id="3-本地方法栈"><a href="#3-本地方法栈" class="headerlink" title="3.本地方法栈"></a>3.本地方法栈</h3><p>&#160; &#160; &#160; &#160;本地方法栈与java虚拟机栈非常相似，虚拟机栈为java方法服务，而本地方法栈为Native方法服务。</p>
<h3 id="4-java堆"><a href="#4-java堆" class="headerlink" title="4.java堆"></a>4.java堆</h3><p>&#160; &#160; &#160; &#160;堆是java虚拟机管理的最大的一块内存。在虚拟机启动的时候创建，并且是线程共享的。java堆主要用于存放对象实例。几乎所有的对象实例都在这里分配内存。<br>&#160; &#160; &#160; &#160;​java堆也是垃圾收集器主要处理的区域。很多时候也被叫做“GC堆”，从内存回收的角度来看，现在收集器基本都采用分代收集法，所有java堆可以细分为新生代和老年代，在细分一点就是Eden空间、From Survivor空间、To Survivor空间。<br>&#160; &#160; &#160; &#160;根据Java虚拟机规范的规定，Java堆可以处于物理上不连续的内存空间中，只要逻辑上是连续的即可，就像我们的磁盘空间一样。在实现时，既可以实现成固定大小的，也可以是可扩展的，不过当前主流的虚拟机都是按照可扩展来实现的（通过-Xmx和-Xms控制）。</p>
<p>&#160; &#160; &#160; &#160;如果在堆中没有内存完成实例分配，并且堆也无法再扩展时，将会抛出OutOfMemoryError异常。</p>
<h3 id="5-方法区"><a href="#5-方法区" class="headerlink" title="5.方法区"></a>5.方法区</h3><p>&#160; &#160; &#160; &#160;方法区是线程共享的一块区域，用于存储已被虚拟机加载的类信息、常量、静态变量、及时编译器编译后的代码等数据。java虚拟机规范吧方法区描述为堆的一个逻辑部分，但是他也有一个别名Non-Heap(非堆)。目的与java堆分区开。<br>&#160; &#160; &#160; &#160;习惯HotSpot虚拟机的开发者，更愿意把方法区成为“永久代”，本质上两种不等价，仅仅因为HotSpot虚拟机的设计团队选择吧GC分代收集扩展到方法区。或者说永久代来实现方法区而已。这样HotSpot的垃圾收集器可以向管理java堆一样管理这部分内存，能够省去专门为方法区编写内存管理代码的工作。<br>&#160; &#160; &#160; &#160;java虚拟机堆方法区的限制非常宽松，不需要联系的内存和可以选择固定大小或者可扩展外，还可以选择不实现垃圾收集。相对而言，垃圾收集行为在这个区域比较少出现，但是并非数据进入了方法区就不收集了。这个区域内存回收的主要目标是针对常量池的回收和对类型的卸载。一般这个区域回收条件比较苛刻，但是回收还是有必要的。<br>&#160; &#160; &#160; &#160;当方法区无法申请到足够的内存的时候，也会抛出OutOfMemoryError异常。</p>
<h3 id="6-运行时常量池"><a href="#6-运行时常量池" class="headerlink" title="6.运行时常量池"></a>6.运行时常量池</h3><p>&#160; &#160; &#160; &#160; 方法区的一部分。Class文件除了有类的版本、字段、方法、接口等描述信息外，还有一项信息就是常量池，用于存放编译器生成的各种字面量和符号引用。这部分内容将在类加载后进入方法区的运行时常量池中存放。在常量池无法在申请到内存会抛出OutOfMemoryError。<br>&#160; &#160; &#160; &#160;运行时常量池有一个重要的特征-具备动态性。java语言不要求常量一定只有在编译器才能产生，运行期间也可以能将新的常量放在池中，这种特性被开发人员利用比较多的便是String类的intern()方法。</p>
<h3 id="7-加课：OutOfMemoryError异常"><a href="#7-加课：OutOfMemoryError异常" class="headerlink" title="7.加课：OutOfMemoryError异常"></a>7.加课：OutOfMemoryError异常</h3><ul>
<li><font color='red'>堆</font></li>
</ul>
<p>java堆用于存储对象实例，只要不断创建对象，并且保证 GC Roots 到对象之间有可达路径，对象数量达到最大堆的容量限制就会产生内存溢出异常。</p>
<p>堆抛出 java.lang.OutOfMemoryError会进一步提示 java heap space.</p>
<p>要解决堆异常，一般需要通过内存映像分析工具对Dump处理的堆转储快照进行分析，重点是确定内存中对象是否是必要的，也就是要先分清楚到底是出现了内存泄漏还是内存溢出。</p>
<p>如果内存泄漏，通过工具查看泄漏对象到GC Roots的引用链。就能找到泄漏对象是通过怎样的路劲与GC Roots相关联并导致垃圾收集器无法自动回收他们的，掌握了泄漏对象的类型信息以及GC Roots引用链的信息，就能比较准确定位泄漏代码的位置。</p>
<p>如果不存在泄漏。检查虚拟机的堆参数与机器物料内存对比，是否还可以调大。代码上查看是否存在某些对象生命周期过长、持有状态时间过长的情况，尝试减少程序运行期间的内存消耗。</p>
<p>设置参数</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">-Xms设置堆的最小空间大小。</span><br><span class="line"></span><br><span class="line">-Xmx设置堆的最大空间大小。</span><br><span class="line"></span><br><span class="line">-XX:+HeapDumpOnOutOfMemoryError:出现内存溢出Dump出当前内存堆转储快照，以便事后分析</span><br></pre></td></tr></table></figure>


<ul>
<li><font color='red'>栈</font></li>
</ul>
<p>栈的容量通过 -Xss 参数设置，java虚拟机描述了两种异常：</p>
<ul>
<li>线程请求的栈深度大于虚拟机有允许的最大深度，抛出 StackOverflowError异常。</li>
<li>虚拟机在扩展栈时无法申请到足够的内存空间，则会抛出OutOfMemoryError异常。</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">-Xms设置堆的最小空间大小。</span><br><span class="line"></span><br><span class="line">-Xmx设置堆的最大空间大小。</span><br><span class="line"></span><br><span class="line">-XX:NewSize设置新生代最小空间大小。</span><br><span class="line"></span><br><span class="line">-XX:MaxNewSize设置新生代最大空间大小。</span><br><span class="line"></span><br><span class="line">-XX:PermSize设置永久代最小空间大小。</span><br><span class="line"></span><br><span class="line">-XX:MaxPermSize设置永久代最大空间大小。</span><br><span class="line"></span><br><span class="line">-Xss设置每个线程的堆栈大小。</span><br><span class="line"></span><br><span class="line">-XX:MetaSpaceSize: 设置元空间大小</span><br><span class="line"></span><br><span class="line">-XX:+PrintGCDetails: 打印GC详细日志</span><br><span class="line"></span><br><span class="line">-XX:SurvivorRatio: 设置新生代中Eden区和s0、s1的大小占比，默认-XX:SurvivorRatio&#x3D;8,Eden:s0:s1&#x3D;8:1:1</span><br><span class="line"></span><br><span class="line">-XX:MaxTenuringThreshold: 设置进入老年代的年龄</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>没有直接设置老年代的参数，但是可以设置堆空间大小和新生代空间大小两个参数来间接控制。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">老年代空间大小&#x3D;堆空间大小-年轻代大空间大小</span><br></pre></td></tr></table></figure>

 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/JVM/" rel="tag">JVM</a></li></ul>

    </footer>
  </div>

    
 
   
</article>

    
    <article
  id="post-blog/firstBlog"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h2 itemprop="name">
  <a class="article-title" href="/2019/05/17/blog/firstBlog/"
    >搭建个人博客</a> 
</h2>
 

    </header>
     
    <div class="article-meta">
      <a href="/2019/05/17/blog/firstBlog/" class="article-date">
  <time datetime="2019-05-17T05:54:09.000Z" itemprop="datePublished">2019-05-17</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/%E8%AE%B0%E5%BD%95/">记录</a>
  </div>
   
    </div>
      
    <div class="article-entry" itemprop="articleBody">
       
  <p>第一次搭建自己的博客，所以想要记录下，搭建的完整过程，方便想要搭建的小白少走弯路。</p>
<h2 id="所需材料"><a href="#所需材料" class="headerlink" title="所需材料"></a>所需材料</h2><ul>
<li>博客的框架使用的是 hexo</li>
<li>hexo 需要依托在 node.js ，所以需要先安装nodejs</li>
<li>GitHubPage: 网站在gitHub上托管</li>
<li>git </li>
</ul>
<h2 id="步骤"><a href="#步骤" class="headerlink" title="步骤"></a>步骤</h2><h3 id="1-安装node-js"><a href="#1-安装node-js" class="headerlink" title="1.安装node.js"></a>1.安装node.js</h3><p>打开官网：<a href="https://nodejs.org/en/">https://nodejs.org/en/</a> , 下载稳定版本的进行安装。</p>
<img src="/2019/05/17/blog/firstBlog/nodejs.png" class="" title="[nodejs.png]">


<p>安装过程 我就忽略了哈， 这个不会 就真的小白了，哈哈（其实是作者懒的在操作一遍   :laughing: ， 有空补上）</p>
<h3 id="2-安装-git"><a href="#2-安装-git" class="headerlink" title="2.安装 git"></a>2.安装 git</h3><p>因为需要将我们的静态网站，部署到github上， 所有需要现在本地安装git.</p>
<h3 id="3-下载并安装hexo"><a href="#3-下载并安装hexo" class="headerlink" title="3.下载并安装hexo"></a>3.下载并安装hexo</h3><h3 id="4-创建博客目录"><a href="#4-创建博客目录" class="headerlink" title="4.创建博客目录"></a>4.创建博客目录</h3><p>新建一个目录，执行下面命令</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo init blog</span><br></pre></td></tr></table></figure>
<p>执行完之后，会自动创建一个hexo目录</p>
<p>从<a href="https://hexo.io/themes/">hexo</a> 选择自己喜欢的主体，下载到本地。放在\themes目录下。</p>
<h3 id="5-修改配置文件根目录下的-config-yml"><a href="#5-修改配置文件根目录下的-config-yml" class="headerlink" title="5.修改配置文件根目录下的 _config.yml"></a>5.修改配置文件根目录下的 _config.yml</h3><ol>
<li>使用自己下载的主题</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"># Extensions</span><br><span class="line">## Plugins: https:&#x2F;&#x2F;hexo.io&#x2F;plugins&#x2F;</span><br><span class="line">## Themes: https:&#x2F;&#x2F;hexo.io&#x2F;themes&#x2F;</span><br><span class="line">theme: ayer</span><br></pre></td></tr></table></figure>

<ol start="2">
<li>在github或者码云上新建一个仓库，仓库名需要和用户名相同</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"># Deployment</span><br><span class="line">## Docs: https:&#x2F;&#x2F;hexo.io&#x2F;docs&#x2F;one-command-deployment</span><br><span class="line">deploy:</span><br><span class="line">  type: git</span><br><span class="line">  repo: https:&#x2F;&#x2F;gitee.com&#x2F;xxx&#x2F;xxxx.git</span><br><span class="line">  branch: master</span><br></pre></td></tr></table></figure>

<h3 id="6-安装插件"><a href="#6-安装插件" class="headerlink" title="6.安装插件"></a>6.安装插件</h3><p>在博客根目录下安装部署插件</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install hexo-deployer-git --save</span><br></pre></td></tr></table></figure>


<h3 id="4-常用操作"><a href="#4-常用操作" class="headerlink" title="4.常用操作"></a>4.常用操作</h3><ul>
<li>创建新的文章<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hexo n &quot;firstBlog&quot;</span><br></pre></td></tr></table></figure>
  会在_posts文件加下创建出一个文件夹（存储文章中图片），和一个md文件,使用下面代码可以引入图片<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">![newfirstBlog.png](newfirstBlog.png)</span><br></pre></td></tr></table></figure>
<img src="newfirstBlog.png" alt="newfirstBlog.png"></li>
</ul>
<p>部署命令</p>
<p>hexo clean # 清除已生成文件及缓存<br>hexo generate # 生成静态页面，简写做hexo g<br>hexo server # 启动本地WEB服务器，简写做hexo s</p>
<p>hexo clean “&amp;&amp;” hexo deploy </p>
<p>hexo clean “&amp;&amp;” hexo generate “&amp;&amp;” hexo deploy </p>
<h2 id="访问地址"><a href="#访问地址" class="headerlink" title="访问地址"></a>访问地址</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https:&#x2F;&#x2F;hhass.gitee.io</span><br></pre></td></tr></table></figure>





 
      <!-- reward -->
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/%E5%8D%9A%E5%AE%A2/" rel="tag">博客</a></li></ul>

    </footer>
  </div>

    
 
   
</article>

    
  </article>
  

  
  <nav class="page-nav">
    
    <a class="extend prev" rel="prev" href="/">上一页</a><a class="page-number" href="/">1</a><span class="page-number current">2</span>
  </nav>
  
</section>
</div>

      <footer class="footer">
  <div class="outer">
    <ul>
      <li>
        Copyrights &copy;
        2020
        <i class="ri-heart-fill heart_icon"></i> G.zero
      </li>
    </ul>
    <ul>
      <li>
        
        
        
        Powered by <a href="https://hexo.io" target="_blank">Hexo</a>
        <span class="division">|</span>
        Theme - <a href="https://github.com/Shen-Yu/hexo-theme-ayer" target="_blank">Ayer</a>
        
      </li>
    </ul>
    <ul>
      <li>
        
        
        <span>
  <span><i class="ri-user-3-fill"></i>Visitors:<span id="busuanzi_value_site_uv"></span></s>
  <span class="division">|</span>
  <span><i class="ri-eye-fill"></i>Views:<span id="busuanzi_value_page_pv"></span></span>
</span>
        
      </li>
    </ul>
    <ul>
      
    </ul>
    <ul>
      
    </ul>
    <ul>
      <li>
        <!-- cnzz统计 -->
        
      </li>
    </ul>
  </div>
</footer>
      <div class="float_btns">
        <div class="totop" id="totop">
  <i class="ri-arrow-up-line"></i>
</div>

<div class="todark" id="todark">
  <i class="ri-moon-line"></i>
</div>

      </div>
    </main>
    <aside class="sidebar on">
      <button class="navbar-toggle"></button>
<nav class="navbar">
  
  <div class="logo">
    <a href="/"><img src="/images/ayer-side.svg" alt="yang-blog"></a>
  </div>
  
  <ul class="nav nav-main">
    
    <li class="nav-item">
      <a class="nav-item-link" href="/">主页</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/archives">归档</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/categories">分类</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags">标签</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/player">播放器</a>
    </li>
    
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  <ul class="nav">
    <li class="nav-item">
      
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
    </aside>
    <script>
      if (window.matchMedia("(max-width: 768px)").matches) {
        document.querySelector('.content').classList.remove('on');
        document.querySelector('.sidebar').classList.remove('on');
      }
    </script>
    <div id="mask"></div>

<!-- #reward -->
<div id="reward">
  <span class="close"><i class="ri-close-line"></i></span>
  <p class="reward-p"><i class="ri-cup-line"></i>请我喝杯咖啡吧~</p>
  <div class="reward-box">
    
    
  </div>
</div>
    
<script src="/js/jquery-2.0.3.min.js"></script>


<script src="/js/lazyload.min.js"></script>

<!-- Tocbot -->

<script src="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.css">
<script src="https://cdn.jsdelivr.net/npm/justifiedGallery@3.7.0/dist/js/jquery.justifiedGallery.min.js"></script>

<script src="/dist/main.js"></script>

<!-- ImageViewer -->

<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">

    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>

    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">

        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>

        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">

            <div class="pswp__top-bar">

                <!--  Controls are self-explanatory. Order can be changed. -->

                <div class="pswp__counter"></div>

                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>

                <button class="pswp__button pswp__button--share" style="display:none" title="Share"></button>

                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>

                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>

                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                        <div class="pswp__preloader__cut">
                            <div class="pswp__preloader__donut"></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div>
            </div>

            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>

            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>

            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>

        </div>

    </div>

</div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/default-skin/default-skin.min.css">
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe-ui-default.min.js"></script>

<script>
    function viewer_init() {
        let pswpElement = document.querySelectorAll('.pswp')[0];
        let $imgArr = document.querySelectorAll(('.article-entry img:not(.reward-img)'))

        $imgArr.forEach(($em, i) => {
            $em.onclick = () => {
                // slider展开状态
                // todo: 这样不好，后面改成状态
                if (document.querySelector('.left-col.show')) return
                let items = []
                $imgArr.forEach(($em2, i2) => {
                    let img = $em2.getAttribute('data-idx', i2)
                    let src = $em2.getAttribute('data-target') || $em2.getAttribute('src')
                    let title = $em2.getAttribute('alt')
                    // 获得原图尺寸
                    const image = new Image()
                    image.src = src
                    items.push({
                        src: src,
                        w: image.width || $em2.width,
                        h: image.height || $em2.height,
                        title: title
                    })
                })
                var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, {
                    index: parseInt(i)
                });
                gallery.init()
            }
        })
    }
    viewer_init()
</script>

<!-- MathJax -->

<!-- Katex -->

<!-- busuanzi  -->


<script src="/js/busuanzi-2.3.pure.min.js"></script>


<!-- ClickLove -->

<!-- ClickBoom1 -->

<!-- ClickBoom2 -->

<!-- CodeCopy -->


<link rel="stylesheet" href="/css/clipboard.css">

<script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<script>
  function wait(callback, seconds) {
    var timelag = null;
    timelag = window.setTimeout(callback, seconds);
  }
  !function (e, t, a) {
    var initCopyCode = function(){
      var copyHtml = '';
      copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
      copyHtml += '<i class="ri-file-copy-2-line"></i><span>COPY</span>';
      copyHtml += '</button>';
      $(".highlight .code pre").before(copyHtml);
      $(".article pre code").before(copyHtml);
      var clipboard = new ClipboardJS('.btn-copy', {
        target: function(trigger) {
          return trigger.nextElementSibling;
        }
      });
      clipboard.on('success', function(e) {
        let $btn = $(e.trigger);
        $btn.addClass('copied');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-checkbox-circle-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPIED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-checkbox-circle-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
      clipboard.on('error', function(e) {
        e.clearSelection();
        let $btn = $(e.trigger);
        $btn.addClass('copy-failed');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-time-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPY FAILED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-time-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
    }
    initCopyCode();
  }(window, document);
</script>


<!-- CanvasBackground -->


    
  </div>
</body>

</html>